<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Menus and Toolbars in GTK+</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, menus, toolbars, GTK+ library, C, Linux">
<meta name="description" content="Menus and Toolbars in GTK+">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Menus and Toolbars in GTK+</h1>


<p>
In this part of the GTK+ programming tutorial, we will work with menus and toolbars. 
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>

<p>
A <b>menubar</b> is one of the most common parts of the GUI application. It is a group of 
commands located in various menus. While in console applications you had to remember 
all those arcane commands, here we have most of the commands grouped into logical parts. 
There are accepted standards that further reduce the amount of time spending to learn 
a new application.
</p>


<h2>Simple menu example</h2>

<p>
In our first example, we will create a menubar with one file menu. The menu will have only
one menu item. By selecting the item the application quits. 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;

  GtkWidget *menubar;
  GtkWidget *filemenu;
  GtkWidget *file;
  GtkWidget *quit;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "menu");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);

  menubar = gtk_menu_bar_new();
  filemenu = gtk_menu_new();

  file = gtk_menu_item_new_with_label("File");
  quit = gtk_menu_item_new_with_label("Quit");

  gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
  gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
  gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
  gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect(G_OBJECT(quit), "activate",
        G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
Creating a menubar is a bit confusing. We must bear in mind that both a 
<b>menubar</b> and <b>menus</b> are derived from the same widget, namely a 
<b>menu shell</b>. <b>menu items</b> are only valid children for menus. 
They are also used to implement submenus. 
</p>

<pre class="explanation">
menubar = gtk_menu_bar_new();
filemenu = gtk_menu_new();
</pre>

<p>
In this code we create a menubar and a menu. 
</p>

<pre class="explanation">
 gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
</pre>

<p>
This code line implements a file menu. The logic is that the menubar 
is a menu shell. file menu is also a menu shell. 
That's why we look at the file menu as a submenu or a subshell. 
</p>

<pre class="explanation">
 gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
</pre>

<p>
Menu items are implemented by calling the 
<b class="keyword">gtk_menu_shell_append()</b> function. menu items
are appended to menu shells. In our case, quit menu item is appended to a 
file menu and also the file menu item is appended to the menubar. 
</p>

<pre class="explanation">
g_signal_connect(G_OBJECT(quit), "activate",
      G_CALLBACK(gtk_main_quit), NULL);
</pre>

<p>
 By selecting the quit menu item, we quit the application.
</p>

<br>
<img src="/img/gui/cgtk/simplemenu.png" alt="Simple menu">
<div class="figure">Figure: Simple menu</div>


<h2>Image menus, mnemonics &amp; accelerators</h2>

<p>
In the next example, we will further explore the functionality that we can use in GTK+.
<b>Accelerators</b> are keyboard shortcuts for activating a menu item. 
<b>Mnemonics</b> are keyboard shortcuts for
GUI elements. They are represented as underlined characters. 
</p>

<p>
Note, that you might have Gnome configured not to show menu images. 
To turn the menu images On/Off, you launch the gconf-editor and
go to /desktop/gnome/interface/menus_have_icons. Check/uncheck the
option.
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;
#include &lt;gdk/gdkkeysyms.h&gt;


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;

  GtkWidget *menubar;
  GtkWidget *filemenu;
  GtkWidget *file;
  GtkWidget *new;
  GtkWidget *open;
  GtkWidget *quit;

  GtkWidget *sep;

  GtkAccelGroup *accel_group = NULL;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "menu");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);

  menubar = gtk_menu_bar_new();
  filemenu = gtk_menu_new();

  accel_group = gtk_accel_group_new();
  gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);

  file = gtk_menu_item_new_with_mnemonic("_File");
  new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
  open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
  sep = gtk_separator_menu_item_new();
  quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group);

  gtk_widget_add_accelerator(quit, "activate", accel_group, 
      GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 


  gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
  gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), new);
  gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open);
  gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep);
  gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
  gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
  gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
      G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect(G_OBJECT(quit), "activate",
      G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
The example shows, how to add an image to our menu item. How to set up an 
accelerator and how to use mnemonics in our GTK+
applications.
</p>

<pre class="explanation">
accel_group = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
...
quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group);
gtk_widget_add_accelerator(quit, "activate", accel_group, 
    GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
</pre>

<p>
An accelerator group is a  group of keyboard accelerators, typically attached to a toplevel window. 
Here we create Ctrl + q keyboard accelerator.
</p>

<pre class="explanation">
 file = gtk_menu_item_new_with_mnemonic("_File");
</pre>

<p>
To create a mnemonic, we call the <b class="keyword">gtk_menu_item_new_with_mnemonic()</b>
function. We select the file menu item by pressing the Alt + F.
</p>

<pre class="explanation">
new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
</pre>

<p>
Here we create two image menu items. By setting the second parameter of the 
function to NULL, we automatically create accelerators.
We provide an image and text for our menu item from internal GTK+ resources.
</p>

<pre class="explanation">
sep = gtk_separator_menu_item_new();
</pre>

<p>
Menu items can be separated by a horizontal separator. This way we can 
put menu items into some logical groups.
</p>


<br>
<img src="/img/gui/cgtk/menu.png" alt="Menu example">
<div class="figure">Figure: Menu example</div>


<h2>Check menu item</h2>

<p>
A <b class="keyword">GtkCheckMenuItem</b> is a menu item with a check box.
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


void toggle_statusbar(GtkWidget *widget, gpointer statusbar) 
{
  if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
    gtk_widget_show(statusbar);
  } else {
    gtk_widget_hide(statusbar);
  }
}


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;

  GtkWidget *menubar;
  GtkWidget *viewmenu;
  GtkWidget *view;
  GtkWidget *tog_stat;
  GtkWidget *statusbar;
  

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "view statusbar");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);

  menubar = gtk_menu_bar_new();
  viewmenu = gtk_menu_new();

  view = gtk_menu_item_new_with_label("View");
  tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");
  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tog_stat), TRUE);

  gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), viewmenu);
  gtk_menu_shell_append(GTK_MENU_SHELL(viewmenu), tog_stat);
  gtk_menu_shell_append(GTK_MENU_SHELL(menubar), view);
  gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);

  statusbar = gtk_statusbar_new();
  gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect(G_OBJECT(tog_stat), "activate", 
        G_CALLBACK(toggle_statusbar), statusbar);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
In our code example we show a check menu item. If the check box is activated, 
the statusbar widget is shown. If not, 
the statusbar is hidden. 
</p>

<pre class="explanation">
 tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");
</pre>

<p>
The <b class="keyword">gtk_check_menu_item_new_with_label()</b> function 
call creates a new check menu item.
</p>

<pre class="explanation">
 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
   gtk_widget_show(statusbar);
 } else {
   gtk_widget_hide(statusbar);
 }
</pre>

<p>
If the check box in the menu item is activated, we show the statusbar widget. 
Otherwise the statusbar is hidden. 
</p>

<br>
<img src="/img/gui/cgtk/checkmenuitem.png" alt="Check menu item">
<div class="figure">Figure: Check menu item</div>


<h2>A toolbar</h2>

<p>
Menus group commands that we can use in application. Toolbars provide a 
quick access to the most frequently used commands.
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;
  
  GtkWidget *toolbar;
  GtkToolItem *new;
  GtkToolItem *open;
  GtkToolItem *save;
  GtkToolItem *sep;
  GtkToolItem *exit;


  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "toolbar");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);


  toolbar = gtk_toolbar_new();
  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);

  gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);

  new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);

  open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), open, -1);

  save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), save, -1);

  sep = gtk_separator_tool_item_new();
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); 

  exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);

  gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);

  g_signal_connect(G_OBJECT(exit), "clicked", 
        G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
The code example creates simple toolbar example. 
</p>

<pre class="explanation">
  toolbar = gtk_toolbar_new();
  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS)
</pre>

<p>
We create a new toolbar. We specify that the toobar buttons show only icons. No text.
</p>

<pre class="explanation">
 new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);
</pre>

<p>
We create a toolbar button from stock. The toolbar buttons are inserted 
into the toolbar by the <b class="keyword">gtk_toolbar_insert()</b> function call. 
</p>

<pre class="explanation">
 sep = gtk_separator_tool_item_new();
 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); 
</pre>

<p>
Here we insert a separator into the toolbar.
</p>

<br>
<img src="/img/gui/cgtk/toolbar.png" alt="Toolbar">
<div class="figure">Figure: Toolbar</div>


<h2>Undo redo</h2>


<p>
The following example demonstrates, how we can inactivate toolbar 
buttons on the toolbar. It is a common practice in GUI
programming. For example the save button. If we save all changes 
of our document to the disk, the save button is inactivated
in most text editors. This way the application indicates to the user, 
that all changes are already saved.
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;
#include &lt;string.h&gt;


void undo_redo(GtkWidget *widget,  gpointer item) 
{
  static int count = 2;
  const char *name = gtk_widget_get_name(widget);

  if ( strcmp(name, "undo") ) {
    count++;
  } else {
    count--;
  }
 
  if (count < 0) {
     gtk_widget_set_sensitive(widget, FALSE);
     gtk_widget_set_sensitive(item, TRUE);
  } 

  if (count > 5) {
     gtk_widget_set_sensitive(widget, FALSE);
     gtk_widget_set_sensitive(item, TRUE);
  }
}


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;

  GtkWidget *toolbar;
  GtkToolItem *undo;
  GtkToolItem *redo;
  GtkToolItem *sep;
  GtkToolItem *exit;


  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "undoredo");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);


  toolbar = gtk_toolbar_new();
  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);

  gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);

  undo = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO);
  gtk_widget_set_name(GTK_WIDGET(undo), "undo");
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), undo, -1);

  redo = gtk_tool_button_new_from_stock(GTK_STOCK_REDO);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), redo, -1);

  sep = gtk_separator_tool_item_new();
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); 

  exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);

  gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);


  g_signal_connect(G_OBJECT(undo), "clicked", 
        G_CALLBACK(undo_redo), redo);

  g_signal_connect(G_OBJECT(redo), "clicked", 
        G_CALLBACK(undo_redo), undo);

  g_signal_connect(G_OBJECT(exit), "clicked", 
        G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
Our example creates undo and redo buttons from the GTK+ stock resources. 
After several clicks each of the 
buttons is inactivated. The buttons are grayed out.
</p>

<pre class="explanation">
 if (count < 0) {
    gtk_widget_set_sensitive(widget, FALSE);
    gtk_widget_set_sensitive(item, TRUE);
 } 

 if (count > 5) {
    gtk_widget_set_sensitive(widget, FALSE);
    gtk_widget_set_sensitive(item, TRUE);
 }
</pre>

<p>
The <b class="keyword">gtk_widget_set_sensitive()</b> function call is used 
to activate/inactivate the 
toolbar buttons.
</p>

<br>
<img src="/img/gui/cgtk/undoredo.png" alt="Undo redo">
<div class="figure">Figure: Undo redo</div>


<hr class="btm">

<p>
In this chapter we have talked about menus and toolbars in GTK+.
</p>

<br>
<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>
<br>

<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified December 4, 2010  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
</div>
</div>

</div> <!-- content  -->

</div> <!-- container  -->

</body>
</html>



